home *** CD-ROM | disk | FTP | other *** search
- /* SchemeWEB -- WEB for Scheme. John D. Ramsdell.
- * Simple support for literate programming in Scheme.
- * This file generates both a Scheme weave program and
- * a Scheme tangle program depending on if TANGLE is defined.
- */
-
- #if !defined lint
- static char ID[] = "$Header: sweb.c,v 1.2 90/07/17 07:25:01 ramsdell Exp $";
- static char copyright[] = "Copyright 1990 by The MITRE Corporation.";
- #endif
- /*
- * Copyright 1990 by The MITRE Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 1, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * For a copy of the GNU General Public License, write to the
- * Free Software Foundation, Inc., 675 Mass Ave,
- * Cambridge, MA 02139, USA.
- */
-
- /* SchemeWEB defines a new source file format in which source lines
- are divided into text and code. Lines of code start with a line
- beginning with '(', and continue until the line that contains the
- matching ')'. The text lines remain, and they are treated as
- comments. If the first character of a text line is ';', it is
- stripped from the output. This is provided for those who want to use
- an unmodified version of their Scheme system's LOAD. When producing a
- document, both the text lines and the code lines are copied into the
- document source file, but the code lines are surrounded by a pair of
- formatting commands, as is comments beginning with ';' within code
- lines. SchemeWEB is currently set up for use with LaTeX. */
-
- /* Define TANGLE to make a program which translates SchemeWEB source
- into Scheme source. */
-
- /* Define SAVE_LEADING_SEMICOLON if you want text lines to be copied
- with any leading semicolon. */
-
- #include <stdio.h>
-
- typedef enum {FALSE, TRUE} bool;
-
- #define putstring(s) (fputs(s, stdout))
-
- #if defined TANGLE
- #define sweb_putchar(c) (putchar(c))
- #define text_putchar(c) (putchar(c))
- #else
- /* Modify the following for use with something other than LaTeX. */
- #define BEGIN_COMMENT "\\notastyped{"
- #define BEGIN_CODE "\\begin{astyped}"
- #define END_CODE "\\end{astyped}"
- #define BEGIN_VERB "\\verb@"
- #define END_VERB "@"
-
- struct {
- unsigned char c;
- char *s;
- } table[] = {
- { 128, "\\c{C}"},
- { 129, "\\\"{u}"},
- { 130, "\\'{e}"},
- { 131, "\\^{a}"},
- { 132, "\\\"{a}"},
- { 133, "\\`{a}"},
- { 134, "\\o{a}"},
- { 135, "\\c{c}"},
- { 136, "\\^{e}"},
- { 137, "\\\"{e}"},
- { 138, "\\`{e}"},
- { 139, "\\\"{\\i}"},
- { 140, "\\^{\\i}"},
- { 141, "\\`{\\i}"},
- { 142, "\\\"{A}"},
- { 143, "\\o{A}"},
- { 144, "\\'{E}"},
- { 145, "\\ae "},
- { 146, "\\AE "},
- { 147, "\\^{o}"},
- { 148, "\\\"{o}"},
- { 149, "\\`{o}"},
- { 150, "\\^{u}"},
- { 151, "\\`{u}"},
- { 152, "\\\"{y}"},
- { 153, "\\\"{O}"},
- { 154, "\\\"{U}"},
- { 156, "\\pound "},
- { 160, "\\'{a}"},
- { 161, "\\'{\\i}"},
- { 162, "\\'{o}"},
- { 163, "\\'{u}"},
- { 164, "\\~{n}"},
- { 165, "\\~{N}"},
- { 0, ""} };
-
- void text_putchar (int c)
- {
- int i;
- for( i = 0; table[i].c; i++ )
- if( table[i].c == c )
- {
- putstring( table[i].s );
- return;
- }
- putchar(c);
- }
-
- void sweb_putchar (c)
- int c;
- { /* Raps \verb around characters */
- switch (c) { /* which LaTeX handles specially. */
- case '\\':
- case '{':
- case '}':
- case '$':
- case '&':
- case '#':
- case '^':
- case '_':
- case '%':
- case '~':
- putstring("\\verb-");
- putchar(c);
- putchar('-');
- break;
- default:
- text_putchar(c);
- }
- }
- #endif
-
- /* Error message for end of file found in code. */
- bool report_eof_in_code()
- {
- fprintf(stderr, "End of file within a code section.\n");
- return TRUE;
- }
-
- /* All input occurs in the following routines so that TAB characters
- can be expanded. TeX treats TAB characters as a space--not what is
- wanted. */
- int ch_buf;
- bool buf_used = FALSE;
- int lineno = 1;
-
- #undef getchar()
- int getchar()
- {
- int c;
- static int spaces = 0; /* Spaces left to print a TAB. */
- static int column = 0; /* Current input column. */
- if (buf_used) {
- buf_used = FALSE;
- return ch_buf;
- }
- if (spaces > 0) {
- spaces--;
- return ' ';
- }
- switch (c = getc(stdin)) {
- case '\t':
- spaces = 7 - (7&column); /* Maybe this should be 7&(~column). */
- column += spaces + 1;
- return ' ';
- case '\n':
- lineno++;
- column = 0;
- return c;
- default:
- column++;
- return c;
- }
- }
-
- void ungetchar(c)
- int c;
- {
- buf_used = TRUE;
- ch_buf = c;
- }
-
- bool copy_text_saw_eof()
- {
- int c;
- while (1) {
- c = getchar();
- if (c == EOF) return TRUE;
- if (c == '\n') return FALSE;
- #if !defined TANGLE
- if (c == '\\')
- {
- putchar(c);
- c = getchar();
- if (c == EOF) return TRUE;
- putchar(c);
- } else
- if (c == '|') /* special verbatim */
- {
- if( (c = getchar()) == '|')
- putchar(c);
- else {
- putstring(BEGIN_VERB);
- do {
- if (c == EOF) return TRUE;
- else putchar(c);
- } while ((c = getchar()) != '|');
- putstring(END_VERB);
- }
- }
- else text_putchar(c);
- #endif
- }
- }
-
- bool copy_comment_saw_eof() /* This copies comments */
- { /* within code sections. */
- #if !defined TANGLE
- putstring(BEGIN_COMMENT);
- putchar(';');
- #endif
- if (copy_text_saw_eof()) return TRUE;
- #if !defined TANGLE
- putchar('}');
- #endif
- putchar('\n');
- return FALSE;
- }
-
- bool after_sexpr_failed() /* Copies comments in a code */
- { /* section that follow a */
- int c; /* complete S-expr. */
- while (1) /* It fails when there is */
- switch (c = getchar()) { /* something other than */
- case EOF: /* white space or a comment, */
- return report_eof_in_code(); /* such as an extra ')'. */
- case ';':
- #if !defined TANGLE
- putstring(BEGIN_COMMENT);
- putchar(c);
- #endif
- if (copy_text_saw_eof()) return report_eof_in_code();
- #if !defined TANGLE
- putchar('}');
- #endif
- putchar('\n');
- return FALSE;
- case '\n':
- putchar(c);
- return FALSE;
- case ' ':
- #if !defined TANGLE
- putchar(c);
- #endif
- break;
- default:
- fprintf(stderr,
- "Found \"%c\" after an S-expr finished.\n",
- c);
- return TRUE;
- }
- }
-
- bool copy_string_saw_eof()
- {
- int c;
- while (1) {
- c = getchar();
- if (c == EOF) return TRUE;
- sweb_putchar(c);
- switch (c) {
- case '"': return FALSE;
- case '\\':
- c = getchar();
- if (c == EOF) return TRUE;
- sweb_putchar(c);
- }
- }
- }
-
- bool copy_symbol_saw_eof()
- {
- int c;
- while (1) {
- c = getchar();
- if (c == EOF) return TRUE;
- sweb_putchar(c);
- switch (c) {
- case '|': return FALSE;
- case '\\':
- c = getchar();
- if (c == EOF) return TRUE;
- sweb_putchar(c);
- }
- }
- }
-
- bool maybe_char_syntax_saw_eof()
- { /* Makes sure that the character */
- int c; /* #\( does not get counted in */
- c = getchar(); /* balancing parentheses. */
- if (c == EOF) return TRUE;
- if (c != '\\') {
- ungetchar(c);
- return FALSE;
- }
- sweb_putchar(c);
- c = getchar();
- if (c == EOF) return TRUE;
- sweb_putchar(c);
- return FALSE;
- }
-
- bool copy_code_failed() /* Copies a code section */
- { /* containing one S-expr. */
- int parens = 1; /* Used to balance parentheses. */
- int c;
- while (1) { /* While parens are not balanced, */
- c = getchar();
- if (c == EOF) /* report failure on EOF and */
- return report_eof_in_code();
- if (c == ';') /* report failure on EOF in a comment. */
- if (copy_comment_saw_eof()) return report_eof_in_code();
- else continue;
- sweb_putchar(c); /* Write the character and then see */
- switch (c) { /* if it requires special handling. */
- case '(':
- parens++;
- break;
- case ')':
- parens--;
- if (parens == 0) /* Parentheses balance! */
- return after_sexpr_failed(); /* Report the result of */
- break; /* post S-expr processing. */
- case '"': /* Report failure on EOF in a string. */
- if (copy_string_saw_eof()) {
- fprintf(stderr, "End of file found within a string.\n");
- return TRUE;
- }
- break;
- case '|': /* Report failure on EOF in a string. */
- if (copy_symbol_saw_eof()) {
- fprintf(stderr, "End of file found within a symbol.\n");
- return TRUE;
- }
- break;
- case '#': /* Report failure on EOF in a character. */
- if (maybe_char_syntax_saw_eof()) return report_eof_in_code();
- break;
- }
- }
- }
-
- int filter()
- {
- int c;
- while (1) { /* At loop start it's in text mode */
- c = getchar(); /* and at the begining of a line. */
- if (c == '(') { /* text mode changed to code mode. */
- #if !defined TANGLE
- putstring(BEGIN_CODE); putchar('\n');
- #endif
- do { /* Copy code. */
- putchar(c);
- if (copy_code_failed()) {
- fprintf(stderr,
- "Error in the code section containing line %d.\n",
- lineno);
- return 1;
- }
- c = getchar(); /* Repeat when there is code */
- } while (c == '('); /* immediately after some code. */
- #if !defined TANGLE
- fputs(END_CODE, stdout); putc('\n', stdout);
- #endif
- }
- /* Found a text line--now in text mode. */
- #if !defined SAVE_LEADING_SEMICOLON
- if (c == ';') c = getchar();
- #endif
- ungetchar(c);
- if (copy_text_saw_eof()) return 0; /* Copy a text line. */
- #if !defined TANGLE
- putchar('\n');
- #endif
- }
- }
-
- void setext( char *name, char *ext, int force )
- {
- int i = strlen(name);
-
- while( --i && name[i] != '\\')
- if( name[i] == '.')
- {
- if( force )
- strcpy( name+i+1, ext );
- return;
- }
- strcpy( name+strlen(name), ".");
- strcpy( name+strlen(name), ext );
- }
-
- int main( int argc, char *argv[] )
- {
- char inname[100], outname[100];
-
- switch (argc)
- {
- case 3:
- strcpy( outname, argv[2] );
- case 2:
- if( argc == 2 )
- strcpy( outname, argv[1] );
- setext( outname,
- #ifdef TANGLE
- "S",
- #else
- "TEX",
- #endif
- argc == 2 );
-
- strcpy( inname, argv[1] );
- setext( inname, "SW", 0 );
-
- if( NULL == freopen( outname, "w", stdout) )
- {
- fprintf(stderr, "Cannot open %s for writing.\n", outname );
- break;
- }
- if( NULL == freopen( inname, "r", stdin) )
- {
- fprintf(stderr, "Cannot open %s for reading.\n", inname );
- break;
- }
- case 1:
- return filter();
- }
- fprintf(stderr,
- #ifdef TANGLE
- "Usage: %s [SchemeWEB file] [Scheme file]\n",
- #else
- "Usage: %s [SchemeWEB file] [LaTeX file]\n",
- #endif
- argv[0]);
- return 1;
- }
-